package com.nebula.salary.portal.controller;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.nebula.salary.common.constants.Const;
import com.nebula.salary.common.constants.ReturnMessage;
import com.nebula.salary.common.result.ResponseCode;
import com.nebula.salary.common.result.ServerResponse;
import com.nebula.salary.common.utils.JwtTokenUtil;
import com.nebula.salary.common.utils.MD5Util;
import com.nebula.salary.common.utils.RegexUtil;
import com.nebula.salary.common.utils.SecurityUtil;
import com.nebula.salary.model.dto.ForgotDto;
import com.nebula.salary.model.dto.LoginDto;
import com.nebula.salary.model.dto.RegisterDto;
import com.nebula.salary.model.dto.UserInfoDto;
import com.nebula.salary.model.pojo.Answer;
import com.nebula.salary.model.pojo.Question;
import com.nebula.salary.model.pojo.User;
import com.nebula.salary.model.vo.LoginUser;
import com.nebula.salary.portal.service.IAnswerService;
import com.nebula.salary.portal.service.IQuestionService;
import com.nebula.salary.portal.service.IUserService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.security.Principal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * <p>
 * 用户表 前端控制器
 * </p>
 *
 * @author codex
 * @since 2022-01-24
 */
@RestController
@RequestMapping("/portal/user")
@Api(tags = "用户登录、注册、找回密码等")
@Transactional(rollbackFor = Exception.class)
public class UserController {
    
    @Autowired
    private IUserService userService;
    
    @Value("${jwt.tokenHead}")
    private String tokenHead;
    
    @Autowired
    private JwtTokenUtil jwtTokenUtil;
    
    @Autowired
    private IQuestionService questionService;
    
    @Autowired
    private IAnswerService answerService;
    
    @ApiOperation("找回密码")
    @PutMapping("/forgot")
    public ServerResponse<String> forgot(@RequestBody ForgotDto forgotDto) {
    	
    	if (Strings.isNullOrEmpty(forgotDto.getUsername())) {
			return ServerResponse.createByErrorMessage(ReturnMessage.USERNAME_CAN_NOT_BE_EMPTY);
		}
    	
    	if (userService.count(new QueryWrapper<User>().eq(User.USERNAME, forgotDto.getUsername())) <= 0) {
    		return ServerResponse.createByErrorMessage("用户名不存在");
    	}

    	if (Strings.isNullOrEmpty(forgotDto.getPassword())) {
			return ServerResponse.createByErrorMessage(ReturnMessage.PASSWORD_CAN_NOT_BE_EMPTY);
		}
    	
    	if (forgotDto.getPassword().length() < Const.PASSWORD_MIN_LENGTH || forgotDto.getPassword().length() > Const.PASSWORD_MAX_LENGTH) {
    		return ServerResponse.createByErrorMessage(ReturnMessage.ILLEGAL_PASSWORD);
    	}
    	
    	return userService.forgot(forgotDto) > 0
    			? ServerResponse.createBySuccessMessage("重置密码成功")
    			: ServerResponse.createByErrorMessage("重置密码失败");
    }
    
    @ApiOperation("验证密保问题答案")
    @GetMapping("/check/{username}/{questionId}/{answer}")
    public ServerResponse<String> checkAnswer(
            @ApiParam(value = "用户名", required = true)
            @PathVariable String username,
            @ApiParam(value = "问题编号", required = true)
            @PathVariable Integer questionId,
            @ApiParam(value = "答案", required = true)
            @PathVariable String answer) {
        
        String md5Answer = MD5Util.MD5EncodeUtf8(answer);
        
        User user = userService.selectUserByUsername(username);
        if (user == null) {
            return ServerResponse.createByErrorMessage("用户名不存在");
        }
        
        Answer info = answerService.getOne(new QueryWrapper<Answer>().eq(Answer.USER_ID, user.getUserId()).eq(Answer.QUESTION_ID, questionId));
        
        if (md5Answer.equals(info.getAnswer())) {
            return ServerResponse.createBySuccess();
        }
        
        return ServerResponse.createByErrorCodeMessage(ResponseCode.ANSWER_IS_ERROR.getCode(), ResponseCode.ANSWER_IS_ERROR.getDesc());
    }
    
    @ApiOperation("获取当前用户的密保问题")
    @GetMapping("/question/{username}")
    public ServerResponse<List<Map<String, Object>>> questionUserList(
            @ApiParam(value = "用户名", required = true)
            @PathVariable String username) {
        
        User user = userService.selectUserByUsername(username);
        if (user == null) {
            return ServerResponse.createByErrorMessage("用户名不存在");
        }
        
        List<Question> list = questionService.questionUserList(user.getUserId());
        
        List<Map<String, Object>> result = Lists.newArrayList();
        
        list.forEach(question -> {
            Map<String, Object> map = Maps.newLinkedHashMap();
            map.put("questionId", question.getQuestionId());
            map.put("question", question.getQuestion());
            result.add(map);
        });
        
        return ServerResponse.createBySuccess(result);
    }
    
    @ApiOperation(value = "重置密码")
    @PutMapping("/resetPwd")
    public ServerResponse<String> resetPassword(String oldPassword, String newPassword) {
        LoginUser loginUser = SecurityUtil.getLoginUser();
        String password = loginUser.getPassword();
        
        if (!SecurityUtil.matchesPassword(oldPassword, password)) {
            return ServerResponse.createByErrorMessage("修改密码失败，旧密码错误");
        }
        if (SecurityUtil.matchesPassword(newPassword, password)) {
            return ServerResponse.createByErrorMessage("新密码不能与旧密码相同");
        }
        
        if (newPassword.length() < Const.PASSWORD_MIN_LENGTH
                || newPassword.length() > Const.PASSWORD_MAX_LENGTH) {
            return ServerResponse.createByErrorMessage(ReturnMessage.ILLEGAL_PASSWORD);
        }
        
        String encryptPassword = SecurityUtil.encryptPassword(newPassword);
        User user = new User();
        user.setUserId(SecurityUtil.getUserId());
        user.setPassword(encryptPassword);
        if (userService.updateById(user)) {
            // 更新缓存数据
            loginUser.getUser().setPassword(encryptPassword);
            jwtTokenUtil.setLoginUser(loginUser);
            return ServerResponse.createBySuccessMessage("修改密码成功");
        }
        
        return ServerResponse.createByErrorMessage("修改密码异常，请联系管理员");
    }
    
    @ApiOperation(value = "更新用户信息")
    @PutMapping("/")
    public ServerResponse<String> updateUserInfo(@RequestBody UserInfoDto userInfoDto) {
        
        if (Strings.isNullOrEmpty(userInfoDto.getRealName())) {
            return ServerResponse.createByErrorMessage(ReturnMessage.NAME_CAN_NOT_BE_EMPTY);
        }
        
        if (!Strings.isNullOrEmpty(userInfoDto.getPhone()) && !RegexUtil.isPhoneLegal(userInfoDto.getPhone())) {
            return ServerResponse.createByErrorMessage(ReturnMessage.ILLEGAL_PHONE);
        }
        
        if (userInfoDto.getAge() != null) {
            if (userInfoDto.getAge() < Const.MIN_AGE || userInfoDto.getAge() > Const.MAX_AGE) {
                return ServerResponse.createByErrorMessage(ReturnMessage.ILLEGAL_AGE);
            }
        }
        User user = new User();
        user.setUserId(SecurityUtil.getUserId());
        BeanUtils.copyProperties(userInfoDto, user);
        
        // 判断手机号码是否存在
        if (userService.checkPhoneUnique(user).equals(Const.NOT_UNIQUE)) {
            return ServerResponse.createByErrorMessage("修改用户'" + SecurityUtil.getUsername() + "'失败，手机号码已存在");
        }
        
        if (userService.updateById(user)) {
            // 更新缓存用户信息
            LoginUser loginUser = SecurityUtil.getLoginUser();
            User redisUser = loginUser.getUser();
            redisUser.setRealName(user.getRealName());
            redisUser.setPhone(user.getPhone());
            redisUser.setAge(user.getAge());
            redisUser.setGender(user.getGender());
            jwtTokenUtil.setLoginUser(loginUser);
            
            return ServerResponse.createBySuccessMessage(ReturnMessage.UPDATE_SUCCESS);
        }
        
        return ServerResponse.createByErrorMessage(ReturnMessage.UPDATE_ERROR);
    }
    
    @ApiOperation(value = "获取登录用户信息", notes = "获取登录用户信息")
    @GetMapping("/")
    public ServerResponse<User> getUserInfo() {
        User user = SecurityUtil.getLoginUser().getUser();
        user.setPassword(null);
        return ServerResponse.createBySuccess(user);
    }
    
    @ApiOperation(value = "验证用户名是否存在", notes = "验证用户名是否存在")
    @GetMapping("/check/{username}")
    public ServerResponse<String> checkUsername(@PathVariable
                                                @ApiParam(value = "用户名", required = true) String username) {
        
        int count = userService.count(new QueryWrapper<User>().eq(User.USERNAME, username));
        
        if (count > 0) {
            return ServerResponse.createByErrorCodeMessage(ResponseCode.USERNAME_IS_EXIST.getCode(), ReturnMessage.USERNAME_IS_EXIST);
        }
        
        return ServerResponse.createByErrorCodeMessage(ResponseCode.USERNAME_ALLOWED_TO_USE.getCode(),
                ReturnMessage.USERNAME_ALLOWED_TO_USE);
    }
    
    @ApiOperation("用户登录")
    @PostMapping("/login")
    public ServerResponse<Map<String, Object>> login(@RequestBody LoginDto loginDto) {
        String token = userService.login(loginDto);
        
        Map<String, Object> map = Maps.newHashMap();
        map.put("tokenHead", tokenHead);
        map.put("token", token);
        
        return ServerResponse.createBySuccessCode(ResponseCode.LOGIN_SUCCESS.getCode(), ReturnMessage.LOGIN_SUCCESS, map);
    }
    
    @ApiOperation("用户注册")
    @PostMapping("/register")
    public ServerResponse<String> register(@RequestBody RegisterDto registerDto) {
        return userService.register(registerDto);
    }
}

